package ssllink

import (
	"bufio"
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"slapp3/backend/sslink/proto"

	"time"

	"go.uber.org/zap"
)

// InitAuth 确定用户组和服务端认证地址 AuthPath
func (sl *Sslink) InitAuth() ([]string, error) {
	var err error
	reqHeaders = make(map[string]string) // 初始化请求头
	reqHeaders["X-Transcend-Version"] = "1"
	reqHeaders["X-Aggregate-Auth"] = "1"

	WebVpnCookie = ""

	config := tls.Config{
		InsecureSkipVerify: Prof.InsecureSkipVerify,
	}
	sl.Conn, err = tls.DialWithDialer(&net.Dialer{Timeout: 6 * time.Second}, "tcp4", Prof.Host, &config)
	if err != nil || sl.Conn == nil {
		sl.log.Error("Failed to connect", zap.Error(err))
		return nil, err
	}

	sl.BufR = bufio.NewReader(sl.Conn)

	dtd := new(proto.DTD)

	err = sl.tplPost(tplInit, "", dtd)
	if err != nil {
		sl.log.Error("Failed to send init request", zap.Error(err))
		return nil, err
	}
	Prof.AuthPath = dtd.Auth.Form.Action
	if Prof.AuthPath == "" {
		Prof.AuthPath = "/"
	}
	Prof.TunnelGroup = dtd.Opaque.TunnelGroup
	Prof.GroupAlias = dtd.Opaque.GroupAlias
	Prof.ConfigHash = dtd.Opaque.ConfigHash

	var allowGroups []string
	if dtd.Auth.IsValid() && dtd.Auth.Form.IsValid() && len(dtd.Auth.Form.Selects) > 0 {
		for _, sel := range dtd.Auth.Form.Selects {
			if sel.Name == "group_list" {
				for _, opt := range sel.Options {
					allowGroups = append(allowGroups, opt.Value)
				}
				break
			}
		}
	}

	if len(allowGroups) == 0 {
		return nil, fmt.Errorf("no available user groups found, please check the server configuration")
	}
	if len(allowGroups) != 0 && InArray(allowGroups, Prof.Group) {
		return nil, nil
	}

	return allowGroups, nil
}

// PasswordAuth 认证成功后，服务端新建 ConnSession，并生成 SessionToken 或者通过 Header 返回 WebVpnCookie
func (sl *Sslink) PasswordAuth() error {
	dtd := new(proto.DTD)
	// 发送用户名或者用户名+密码
	err := sl.tplPost(tplAuthReply, Prof.AuthPath, dtd)
	if err != nil {
		return err
	}

	// 兼容两步登陆，如必要则再次发送
	if dtd.Type == "auth-request" && dtd.Auth != nil && dtd.Auth.Error != nil {
		dtd = new(proto.DTD)
		err = sl.tplPost(tplAuthReply, Prof.AuthPath, dtd)
		if err != nil {
			return err
		}
	}

	// 用户名、密码等错误
	if dtd.Type == "auth-request" {
		if dtd.Auth.IsValid() && dtd.Auth.Error != nil {
			return fmt.Errorf(dtd.Auth.Error.Text, dtd.Auth.Error.Param1)
		}
		return errors.New(dtd.Auth.Message)
	}
	// AnyConnect 客户端支持 XML，OpenConnect 不使用 XML，而是使用 Cookie 反馈给客户端登陆状态
	sl.Session = NewSession(Prof, sl.config, sl.log)
	sl.Session.SessionToken = dtd.SessionToken
	// 兼容 OpenConnect
	if WebVpnCookie != "" {
		sl.Session.SessionToken = WebVpnCookie
	}
	return nil
}
